//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.ruoyi.common.utils.jkalman.jama;
import com.ruoyi.common.utils.jkalman.jama.util.Maths;

import java.io.Serializable;

public class EigenvalueDecomposition implements Serializable {
    private int n;
    private boolean issymmetric;
    private double[] d;
    private double[] e;
    private double[][] V;
    private double[][] H;
    private double[] ort;
    private transient double cdivr;
    private transient double cdivi;

    private void tred2() {
        int i;
        for(i = 0; i < this.n; ++i) {
            this.d[i] = this.V[this.n - 1][i];
        }

        double scale;
        double[] var10000;
        for(i = this.n - 1; i > 0; --i) {
            scale = 0.0;
            double h = 0.0;

            int j;
            for(j = 0; j < i; ++j) {
                scale += Math.abs(this.d[j]);
            }

            if (scale == 0.0) {
                this.e[i] = this.d[i - 1];

                for(j = 0; j < i; ++j) {
                    this.d[j] = this.V[i - 1][j];
                    this.V[i][j] = 0.0;
                    this.V[j][i] = 0.0;
                }
            } else {
                for(j = 0; j < i; ++j) {
                    var10000 = this.d;
                    var10000[j] /= scale;
                    h += this.d[j] * this.d[j];
                }

                double f = this.d[i - 1];
                double g = Math.sqrt(h);
                if (f > 0.0) {
                    g = -g;
                }

                this.e[i] = scale * g;
                h -= f * g;
                this.d[i - 1] = f - g;

                int s;
                for(s = 0; j < i; ++s) {
                    this.e[s] = 0.0;
                }

                s = 0;

                label156:
                while(true) {
                    if (j >= i) {
                        f = 0.0;

                        for(j = 0; j < i; ++j) {
                            var10000 = this.e;
                            var10000[j] /= h;
                            f += this.e[j] * this.d[j];
                        }

                        double hh = f / (h + h);

                        int n;
                        for(n = 0; n < i; ++n) {
                            var10000 = this.e;
                            var10000[n] -= hh * this.d[n];
                        }

                        n = 0;

                        while(true) {
                            if (j >= i) {
                                break label156;
                            }

                            f = this.d[j];
                            g = this.e[j];

                            for(int k = j; k <= i - 1; ++k) {
                                var10000 = this.V[k];
                                var10000[j] -= f * this.e[k] + g * this.d[k];
                            }

                            this.d[j] = this.V[i - 1][j];
                            this.V[i][j] = 0.0;
                            ++j;
                        }
                    }

                    f = this.d[j];
                    this.V[j][i] = f;
                    g = this.e[j] + this.V[j][j] * f;

                    for(int k = j + 1; k <= i - 1; ++k) {
                        g += this.V[k][j] * this.d[k];
                        var10000 = this.e;
                        var10000[k] += this.V[k][j] * f;
                    }

                    this.e[j] = g;
                    ++j;
                }
            }

            this.d[i] = h;
        }

        for(i = 0; i < this.n - 1; ++i) {
            this.V[this.n - 1][i] = this.V[i][i];
            this.V[i][i] = 1.0;
            scale = this.d[i + 1];
            int j;
            if (scale != 0.0) {
                for(j = 0; j <= i; ++j) {
                    this.d[j] = this.V[j][i + 1] / scale;
                }

                for(j = 0; j <= i; ++j) {
                    double g = 0.0;

                    int k;
                    for(k = 0; k <= i; ++k) {
                        g += this.V[k][i + 1] * this.V[k][j];
                    }

                    for(k = 0; k <= i; ++k) {
                        var10000 = this.V[k];
                        var10000[j] -= g * this.d[k];
                    }
                }
            }

            for(j = 0; j <= i; ++j) {
                this.V[j][i + 1] = 0.0;
            }
        }

        for(i = 0; i < this.n; ++i) {
            this.d[i] = this.V[this.n - 1][i];
            this.V[this.n - 1][i] = 0.0;
        }

        this.V[this.n - 1][this.n - 1] = 1.0;
        this.e[0] = 0.0;
    }

    private void tql2() {
        for(int i = 1; i < this.n; ++i) {
            this.e[i - 1] = this.e[i];
        }

        this.e[this.n - 1] = 0.0;
        double f = 0.0;
        double tst1 = 0.0;
        double eps = Math.pow(2.0, -52.0);

        int l;
        int m;
        for(l = 0; l < this.n; ++l) {
            tst1 = Math.max(tst1, Math.abs(this.d[l]) + Math.abs(this.e[l]));

            for(m = l; m < this.n && !(Math.abs(this.e[m]) <= eps * tst1); ++m) {
            }

            if (m > l) {
                int iter = 0;

                do {
                    ++iter;
                    double g = this.d[l];
                    double p = (this.d[l + 1] - g) / (2.0 * this.e[l]);
                    double r = Maths.hypot(p, 1.0);
                    if (p < 0.0) {
                        r = -r;
                    }

                    this.d[l] = this.e[l] / (p + r);
                    this.d[l + 1] = this.e[l] * (p + r);
                    double dl1 = this.d[l + 1];
                    double h = g - this.d[l];

                    for(int i = l + 2; i < this.n; ++i) {
                        double[] var10000 = this.d;
                        var10000[i] -= h;
                    }

                    f += h;
                    p = this.d[m];
                    double c = 1.0;
                    double c2 = c;
                    double c3 = c;
                    double el1 = this.e[l + 1];
                    double s = 0.0;
                    double s2 = 0.0;

                    for(int i = m - 1; i >= l; --i) {
                        c3 = c2;
                        c2 = c;
                        s2 = s;
                        g = c * this.e[i];
                        h = c * p;
                        r = Maths.hypot(p, this.e[i]);
                        this.e[i + 1] = s * r;
                        s = this.e[i] / r;
                        c = p / r;
                        p = c * this.d[i] - s * g;
                        this.d[i + 1] = h + s * (c * g + s * this.d[i]);

                        for(int k = 0; k < this.n; ++k) {
                            h = this.V[k][i + 1];
                            this.V[k][i + 1] = s * this.V[k][i] + c * h;
                            this.V[k][i] = c * this.V[k][i] - s * h;
                        }
                    }

                    p = -s * s2 * c3 * el1 * this.e[l] / dl1;
                    this.e[l] = s * p;
                    this.d[l] = c * p;
                } while(Math.abs(this.e[l]) > eps * tst1);
            }

            this.d[l] += f;
            this.e[l] = 0.0;
        }

        for(l = 0; l < this.n - 1; ++l) {
            m = l;
            double p = this.d[l];

            int j;
            for(j = l + 1; j < this.n; ++j) {
                if (this.d[j] < p) {
                    m = j;
                    p = this.d[j];
                }
            }

            if (m != l) {
                this.d[m] = this.d[l];
                this.d[l] = p;

                for(j = 0; j < this.n; ++j) {
                    p = this.V[j][l];
                    this.V[j][l] = this.V[j][m];
                    this.V[j][m] = p;
                }
            }
        }

    }

    private void orthes() {
        int low = 0;
        int high = this.n - 1;

        int m;
        double[] var10000;
        for(m = low + 1; m <= high - 1; ++m) {
            double scale = 0.0;

            for(int i = m; i <= high; ++i) {
                scale += Math.abs(this.H[i][m - 1]);
            }

            if (scale != 0.0) {
                double h = 0.0;

                for(int i = high; i >= m; --i) {
                    this.ort[i] = this.H[i][m - 1] / scale;
                    h += this.ort[i] * this.ort[i];
                }

                double g = Math.sqrt(h);
                if (this.ort[m] > 0.0) {
                    g = -g;
                }

                h -= this.ort[m] * g;
                this.ort[m] -= g;

                int i;
                double f;
                int j;
                for(i = m; i < this.n; ++i) {
                    f = 0.0;

                    for(j = high; j >= m; --j) {
                        f += this.ort[j] * this.H[j][i];
                    }

                    f /= h;

                    for(j = m; j <= high; ++j) {
                        var10000 = this.H[j];
                        var10000[i] -= f * this.ort[j];
                    }
                }

                for(i = 0; i <= high; ++i) {
                    f = 0.0;

                    for(j = high; j >= m; --j) {
                        f += this.ort[j] * this.H[i][j];
                    }

                    f /= h;

                    for(j = m; j <= high; ++j) {
                        var10000 = this.H[i];
                        var10000[j] -= f * this.ort[j];
                    }
                }

                this.ort[m] = scale * this.ort[m];
                this.H[m][m - 1] = scale * g;
            }
        }

        int j;
        for(m = 0; m < this.n; ++m) {
            for(j = 0; j < this.n; ++j) {
                this.V[m][j] = m == j ? 1.0 : 0.0;
            }
        }

        for(m = high - 1; m >= low + 1; --m) {
            if (this.H[m][m - 1] != 0.0) {
                for(j = m + 1; j <= high; ++j) {
                    this.ort[j] = this.H[j][m - 1];
                }

                for(j = m; j <= high; ++j) {
                    double g = 0.0;

                    int i;
                    for(i = m; i <= high; ++i) {
                        g += this.ort[i] * this.V[i][j];
                    }

                    g = g / this.ort[m] / this.H[m][m - 1];

                    for(i = m; i <= high; ++i) {
                        var10000 = this.V[i];
                        var10000[j] += g * this.ort[i];
                    }
                }
            }
        }

    }

    private void cdiv(double xr, double xi, double yr, double yi) {
        double r;
        double d;
        if (Math.abs(yr) > Math.abs(yi)) {
            r = yi / yr;
            d = yr + r * yi;
            this.cdivr = (xr + r * xi) / d;
            this.cdivi = (xi - r * xr) / d;
        } else {
            r = yr / yi;
            d = yi + r * yr;
            this.cdivr = (r * xr + xi) / d;
            this.cdivi = (r * xi - xr) / d;
        }

    }

    private void hqr2() {
        int nn = this.n;
        int n = nn - 1;
        int low = 0;
        int high = nn - 1;
        double eps = Math.pow(2.0, -52.0);
        double exshift = 0.0;
        double p = 0.0;
        double q = 0.0;
        double r = 0.0;
        double s = 0.0;
        double z = 0.0;
        double norm = 0.0;

        int iter;
        int l;
        for(iter = 0; iter < nn; ++iter) {
            if (iter < low | iter > high) {
                this.d[iter] = this.H[iter][iter];
                this.e[iter] = 0.0;
            }

            for(l = Math.max(iter - 1, 0); l < nn; ++l) {
                norm += Math.abs(this.H[iter][l]);
            }
        }

        iter = 0;

        while(true) {
            double w;
            double x;
            double y;
            int m;
            int k;
            while(n >= low) {
                for(l = n; l > low; --l) {
                    s = Math.abs(this.H[l - 1][l - 1]) + Math.abs(this.H[l][l]);
                    if (s == 0.0) {
                        s = norm;
                    }

                    if (Math.abs(this.H[l][l - 1]) < eps * s) {
                        break;
                    }
                }

                if (l == n) {
                    this.H[n][n] += exshift;
                    this.d[n] = this.H[n][n];
                    this.e[n] = 0.0;
                    --n;
                    iter = 0;
                } else if (l == n - 1) {
                    w = this.H[n][n - 1] * this.H[n - 1][n];
                    p = (this.H[n - 1][n - 1] - this.H[n][n]) / 2.0;
                    q = p * p + w;
                    z = Math.sqrt(Math.abs(q));
                    this.H[n][n] += exshift;
                    this.H[n - 1][n - 1] += exshift;
                    x = this.H[n][n];
                    if (q >= 0.0) {
                        if (p >= 0.0) {
                            z += p;
                        } else {
                            z = p - z;
                        }

                        this.d[n - 1] = x + z;
                        this.d[n] = this.d[n - 1];
                        if (z != 0.0) {
                            this.d[n] = x - w / z;
                        }

                        this.e[n - 1] = 0.0;
                        this.e[n] = 0.0;
                        x = this.H[n][n - 1];
                        s = Math.abs(x) + Math.abs(z);
                        p = x / s;
                        q = z / s;
                        r = Math.sqrt(p * p + q * q);
                        p /= r;
                        q /= r;

                        for(m = n - 1; m < nn; ++m) {
                            z = this.H[n - 1][m];
                            this.H[n - 1][m] = q * z + p * this.H[n][m];
                            this.H[n][m] = q * this.H[n][m] - p * z;
                        }

                        for(m = 0; m <= n; ++m) {
                            z = this.H[m][n - 1];
                            this.H[m][n - 1] = q * z + p * this.H[m][n];
                            this.H[m][n] = q * this.H[m][n] - p * z;
                        }

                        for(m = low; m <= high; ++m) {
                            z = this.V[m][n - 1];
                            this.V[m][n - 1] = q * z + p * this.V[m][n];
                            this.V[m][n] = q * this.V[m][n] - p * z;
                        }
                    } else {
                        this.d[n - 1] = x + p;
                        this.d[n] = x + p;
                        this.e[n - 1] = z;
                        this.e[n] = -z;
                    }

                    n -= 2;
                    iter = 0;
                } else {
                    x = this.H[n][n];
                    y = 0.0;
                    w = 0.0;
                    if (l < n) {
                        y = this.H[n - 1][n - 1];
                        w = this.H[n][n - 1] * this.H[n - 1][n];
                    }

                    double[] var10000;
                    if (iter == 10) {
                        exshift += x;

                        for(m = low; m <= n; ++m) {
                            var10000 = this.H[m];
                            var10000[m] -= x;
                        }

                        s = Math.abs(this.H[n][n - 1]) + Math.abs(this.H[n - 1][n - 2]);
                        x = y = 0.75 * s;
                        w = -0.4375 * s * s;
                    }

                    if (iter == 30) {
                        s = (y - x) / 2.0;
                        s = s * s + w;
                        if (s > 0.0) {
                            s = Math.sqrt(s);
                            if (y < x) {
                                s = -s;
                            }

                            s = x - w / ((y - x) / 2.0 + s);

                            for(m = low; m <= n; ++m) {
                                var10000 = this.H[m];
                                var10000[m] -= s;
                            }

                            exshift += s;
                            w = 0.964;
                            y = 0.964;
                            x = 0.964;
                        }
                    }

                    ++iter;

                    for(m = n - 2; m >= l; --m) {
                        z = this.H[m][m];
                        r = x - z;
                        s = y - z;
                        p = (r * s - w) / this.H[m + 1][m] + this.H[m][m + 1];
                        q = this.H[m + 1][m + 1] - z - r - s;
                        r = this.H[m + 2][m + 1];
                        s = Math.abs(p) + Math.abs(q) + Math.abs(r);
                        p /= s;
                        q /= s;
                        r /= s;
                        if (m == l || Math.abs(this.H[m][m - 1]) * (Math.abs(q) + Math.abs(r)) < eps * Math.abs(p) * (Math.abs(this.H[m - 1][m - 1]) + Math.abs(z) + Math.abs(this.H[m + 1][m + 1]))) {
                            break;
                        }
                    }

                    for(k = m + 2; k <= n; ++k) {
                        this.H[k][k - 2] = 0.0;
                        if (k > m + 2) {
                            this.H[k][k - 3] = 0.0;
                        }
                    }

                    for(k = m; k <= n - 1; ++k) {
                        boolean notlast = k != n - 1;
                        if (k != m) {
                            p = this.H[k][k - 1];
                            q = this.H[k + 1][k - 1];
                            r = notlast ? this.H[k + 2][k - 1] : 0.0;
                            x = Math.abs(p) + Math.abs(q) + Math.abs(r);
                            if (x != 0.0) {
                                p /= x;
                                q /= x;
                                r /= x;
                            }
                        }

                        if (x == 0.0) {
                            break;
                        }

                        s = Math.sqrt(p * p + q * q + r * r);
                        if (p < 0.0) {
                            s = -s;
                        }

                        if (s != 0.0) {
                            if (k != m) {
                                this.H[k][k - 1] = -s * x;
                            } else if (l != m) {
                                this.H[k][k - 1] = -this.H[k][k - 1];
                            }

                            p += s;
                            x = p / s;
                            y = q / s;
                            z = r / s;
                            q /= p;
                            r /= p;

                            int i;
                            for(i = k; i < nn; ++i) {
                                p = this.H[k][i] + q * this.H[k + 1][i];
                                if (notlast) {
                                    p += r * this.H[k + 2][i];
                                    this.H[k + 2][i] -= p * z;
                                }

                                this.H[k][i] -= p * x;
                                this.H[k + 1][i] -= p * y;
                            }

                            for(i = 0; i <= Math.min(n, k + 3); ++i) {
                                p = x * this.H[i][k] + y * this.H[i][k + 1];
                                if (notlast) {
                                    p += z * this.H[i][k + 2];
                                    this.H[i][k + 2] -= p * r;
                                }

                                this.H[i][k] -= p;
                                this.H[i][k + 1] -= p * q;
                            }

                            for(i = low; i <= high; ++i) {
                                p = x * this.V[i][k] + y * this.V[i][k + 1];
                                if (notlast) {
                                    p += z * this.V[i][k + 2];
                                    this.V[i][k + 2] -= p * r;
                                }

                                this.V[i][k] -= p;
                                this.V[i][k + 1] -= p * q;
                            }
                        }
                    }
                }
            }

            if (norm == 0.0) {
                return;
            }

            for(n = nn - 1; n >= 0; --n) {
                p = this.d[n];
                q = this.e[n];
                double t;
                if (q == 0.0) {
                    l = n;
                    this.H[n][n] = 1.0;

                    for(m = n - 1; m >= 0; --m) {
                        w = this.H[m][m] - p;
                        r = 0.0;

                        for(k = l; k <= n; ++k) {
                            r += this.H[m][k] * this.H[k][n];
                        }

                        if (this.e[m] < 0.0) {
                            z = w;
                            s = r;
                        } else {
                            l = m;
                            if (this.e[m] == 0.0) {
                                if (w != 0.0) {
                                    this.H[m][n] = -r / w;
                                } else {
                                    this.H[m][n] = -r / (eps * norm);
                                }
                            } else {
                                x = this.H[m][m + 1];
                                y = this.H[m + 1][m];
                                q = (this.d[m] - p) * (this.d[m] - p) + this.e[m] * this.e[m];
                                t = (x * s - z * r) / q;
                                this.H[m][n] = t;
                                if (Math.abs(x) > Math.abs(z)) {
                                    this.H[m + 1][n] = (-r - w * t) / x;
                                } else {
                                    this.H[m + 1][n] = (-s - y * t) / z;
                                }
                            }

                            t = Math.abs(this.H[m][n]);
                            if (eps * t * t > 1.0) {
                                for(k = m; k <= n; ++k) {
                                    this.H[k][n] /= t;
                                }
                            }
                        }
                    }
                } else if (q < 0.0) {
                    l = n - 1;
                    if (Math.abs(this.H[n][n - 1]) > Math.abs(this.H[n - 1][n])) {
                        this.H[n - 1][n - 1] = q / this.H[n][n - 1];
                        this.H[n - 1][n] = -(this.H[n][n] - p) / this.H[n][n - 1];
                    } else {
                        this.cdiv(0.0, -this.H[n - 1][n], this.H[n - 1][n - 1] - p, q);
                        this.H[n - 1][n - 1] = this.cdivr;
                        this.H[n - 1][n] = this.cdivi;
                    }

                    this.H[n][n - 1] = 0.0;
                    this.H[n][n] = 1.0;

                    for(m = n - 2; m >= 0; --m) {
                        double ra = 0.0;
                        double sa = 0.0;

                        int j;
                        for(j = l; j <= n; ++j) {
                            ra += this.H[m][j] * this.H[j][n - 1];
                            sa += this.H[m][j] * this.H[j][n];
                        }

                        w = this.H[m][m] - p;
                        if (this.e[m] < 0.0) {
                            z = w;
                            r = ra;
                            s = sa;
                        } else {
                            l = m;
                            if (this.e[m] == 0.0) {
                                this.cdiv(-ra, -sa, w, q);
                                this.H[m][n - 1] = this.cdivr;
                                this.H[m][n] = this.cdivi;
                            } else {
                                x = this.H[m][m + 1];
                                y = this.H[m + 1][m];
                                double vr = (this.d[m] - p) * (this.d[m] - p) + this.e[m] * this.e[m] - q * q;
                                double vi = (this.d[m] - p) * 2.0 * q;
                                if (vr == 0.0 & vi == 0.0) {
                                    vr = eps * norm * (Math.abs(w) + Math.abs(q) + Math.abs(x) + Math.abs(y) + Math.abs(z));
                                }

                                this.cdiv(x * r - z * ra + q * sa, x * s - z * sa - q * ra, vr, vi);
                                this.H[m][n - 1] = this.cdivr;
                                this.H[m][n] = this.cdivi;
                                if (Math.abs(x) > Math.abs(z) + Math.abs(q)) {
                                    this.H[m + 1][n - 1] = (-ra - w * this.H[m][n - 1] + q * this.H[m][n]) / x;
                                    this.H[m + 1][n] = (-sa - w * this.H[m][n] - q * this.H[m][n - 1]) / x;
                                } else {
                                    this.cdiv(-r - y * this.H[m][n - 1], -s - y * this.H[m][n], z, q);
                                    this.H[m + 1][n - 1] = this.cdivr;
                                    this.H[m + 1][n] = this.cdivi;
                                }
                            }

                            t = Math.max(Math.abs(this.H[m][n - 1]), Math.abs(this.H[m][n]));
                            if (eps * t * t > 1.0) {
                                for(j = m; j <= n; ++j) {
                                    this.H[j][n - 1] /= t;
                                    this.H[j][n] /= t;
                                }
                            }
                        }
                    }
                }
            }

            for(l = 0; l < nn; ++l) {
                if (l < low | l > high) {
                    for(m = l; m < nn; ++m) {
                        this.V[l][m] = this.H[l][m];
                    }
                }
            }

            for(l = nn - 1; l >= low; --l) {
                for(m = low; m <= high; ++m) {
                    z = 0.0;

                    for(k = low; k <= Math.min(l, high); ++k) {
                        z += this.V[m][k] * this.H[k][l];
                    }

                    this.V[m][l] = z;
                }
            }

            return;
        }
    }

    public EigenvalueDecomposition(Matrix Arg) {
        double[][] A = Arg.getArray();
        this.n = Arg.getColumnDimension();
        this.V = new double[this.n][this.n];
        this.d = new double[this.n];
        this.e = new double[this.n];
        this.issymmetric = true;

        int j;
        int i;
        for(j = 0; j < this.n & this.issymmetric; ++j) {
            for(i = 0; i < this.n & this.issymmetric; ++i) {
                this.issymmetric = A[i][j] == A[j][i];
            }
        }

        if (this.issymmetric) {
            for(j = 0; j < this.n; ++j) {
                for(i = 0; i < this.n; ++i) {
                    this.V[j][i] = A[j][i];
                }
            }

            this.tred2();
            this.tql2();
        } else {
            this.H = new double[this.n][this.n];
            this.ort = new double[this.n];

            for(j = 0; j < this.n; ++j) {
                for(i = 0; i < this.n; ++i) {
                    this.H[i][j] = A[i][j];
                }
            }

            this.orthes();
            this.hqr2();
        }

    }

    public Matrix getV() {
        return new Matrix(this.V, this.n, this.n);
    }

    public double[] getRealEigenvalues() {
        return this.d;
    }

    public double[] getImagEigenvalues() {
        return this.e;
    }

    public Matrix getD() {
        Matrix X = new Matrix(this.n, this.n);
        double[][] D = X.getArray();

        for(int i = 0; i < this.n; ++i) {
            for(int j = 0; j < this.n; ++j) {
                D[i][j] = 0.0;
            }

            D[i][i] = this.d[i];
            if (this.e[i] > 0.0) {
                D[i][i + 1] = this.e[i];
            } else if (this.e[i] < 0.0) {
                D[i][i - 1] = this.e[i];
            }
        }

        return X;
    }
}
